from Tkinter import BOTH,NONE,X,Y,BOTTOM,TOP,LEFT,RIGHT
from djcontrolutil import H,V

#Should also provide a good way to bind events.
#Should expose methods common to all widgets

class DjControl():
	_basecontrol = None

	def __getattr__(self, strAttribute):
		if strAttribute=='basecontrol': return self._basecontrol
		return self._getorset(False, strAttribute)
		
	def __setattr__(self, strAttribute, value):
		return self._getorset(True, strAttribute, value)
	
	def destroy(self): #Remove
		self.basecontrol.destroy()
	
	def pack(self,*args, **options):
		""" Place on form using pack() method."""
		self.basecontrol.pack(**options)
		return self
	def grid(self,*args, **options):
		""" Place on form using grid() method."""
		self.basecontrol.grid(**options)
		return self
	def place(self,*args, **options):
		""" Place on form using place() method."""
		self.basecontrol.place(**options)
		return self
		
	def add(self, layout='',pad=None,marker=H):
		"""A wrapper around pack(). Layout is one of '', 'fill','fillX','fillY' or 'expand', 'fill,expand','fillX,expand', and so on. Pad is either an integer (padding) or a tuple for horizontal padding and vertical padding."""
		kwds={}
		if layout:
			kwds['expand'] = 0
			
			layout=layout.split(',')
			for s in layout:
				s=s.lower()
				if s=='expand':
					kwds['expand'] = 1
				elif s=='fill':
					kwds['fill'] = BOTH
				elif s=='fillx':
					kwds['fill'] = X
				elif s=='filly':
					kwds['fill'] = Y
			
		if pad!=None:
			if isinstance(pad,tuple) or isinstance(pad,list):
				kwds['padx']=pad[0]
				kwds['pady']=pad[1]
			else:
				kwds['padx']=pad
				kwds['pady']=pad
				
		
		if marker==V: kwds['side']=TOP
		else: kwds['side']=LEFT
		#Otherwise, use the default, packing to the side horizontally.
		
		self.pack(**kwds)
		return self
	
	def tkmethod(self, strMethod, *args, **kwargs):
		""" Call an arbitrary method on the underlying tkinter control. If you need to, you can access the "basecontrol" property as well. """
		if strMethod not in self.basecontrol.__dict__:
			raise RuntimeError, 'Tkinter method not found. Check the tkinter documentation.'
		return self.basecontrol.__dict__[strMethod](*args, **kwargs)
		
	def set_many(self,**options): #take note that these are dj, not tk options.
		"""Set many properties of the control at once."""
		# It is inefficient to do this instead of config which could set many properties at once, but I'm not worried about this for now
		for option in options:
			self._getorset(True, option, options[option])
	
	def _getorset(self, bSet, strAttribute, value=None):
		#These can be set as C#-like properties. They both are handled in the same 
		
		# Many properties are a simple wrapper of a Tkinter setting. 
		# _autoProperties contains a 
		if self._autoProperties!=None and strAttribute in self._autoProperties:
			strImplProp = self._autoProperties[strAttribute][0]
			fnSetWrapper = self._autoProperties[strAttribute][1]
			fnGetWrapper = self._autoProperties[strAttribute][2]
			if bSet:
				if fnSetWrapper==None: self.basecontrol[strImplProp] = value
				else: self.basecontrol[strImplProp] = fnSetWrapper(value)
				self.basecontrol.update_idletasks()
			else: 
				if fnGetWrapper==None: return self.basecontrol[strImplProp]
				else: return fnGetWrapper(self.basecontrol[strImplProp])
					
		elif strAttribute in self._customProperties:
			# Some have manual properties that are more complicated than just a conversion.
			return self._lookupCustomProperties(bSet, strAttribute, value)
		else:
			# Asymmetry between get and set. The override ALWAYS occurs for set, but for get, it checks existing members first.
			if bSet:
				# Set as usual
				if strAttribute[0]=='_' or strAttribute in ['basecontrol']:
					#~ print strAttribute, 'value:', value, 'o'
					self.__dict__[strAttribute] = value #~ object.__setattr__(self, strAttribute, value)
				else:
					raise AttributeError, strAttribute
			else:
				# This means that the usual method already failed.
				raise AttributeError, strAttribute
	
	# Events
	def bind(self, *args):
		self.basecontrol.bind(*args)
	
	# Base methods and properties.
	def focus(self):
		self.basecontrol.focus_set()
	def has_focus(self):
		return self.basecontrol.focus_get()
	
